import { startTransition } from 'react';
import { DROPDOWN_OPTIONS } from 'configs/searchPage';
import history from 'history/browser';
import { ILocalStore } from 'hooks/useLocalStore';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { GithubOwnersMatchApi, normalizeGithubOwnersMatch } from 'store/models';
import RootStore from 'store/RootStore';
import ApiStore from 'store/RootStore/ApiStore';
import SearchPageStore from 'store/SearchPageStore';

import { Option } from 'components/MultiDropdown';
import { debounce, searchCreate, throttle } from 'utils';

type PrivateFields = '_githubOwnersMatch' | '_inputValue' | '_dropdownValues';

export default class SearchContainerStore implements ILocalStore {
    private readonly _ApiStore = new ApiStore();
    private readonly _ThrottledFn = throttle((value: string) => this.fetchOrganizationsMatch(value), 500);
    private readonly _DebouncedFn = debounce((value: string) => this.fetchOrganizationsMatch(value), 500);
    private _githubOwnersMatch: Option[] = [];
    private readonly _navigateReaction: IReactionDisposer;
    private _dropdownValues: Option[] = [];
    private _inputValue = new URLSearchParams(window.location.search).get('search') ?? undefined;
    //private readonly _searchPageStore: SearchPageStore;
    constructor(searchPageStore: SearchPageStore) {
        makeObservable<SearchContainerStore, PrivateFields>(this, {
            _githubOwnersMatch: observable,
            _dropdownValues: observable.ref,
            _inputValue: observable,
            inputValue: computed,
            dropdownValues: computed,
            githubOwnersMatch: computed,
            setDropdownValues: action.bound,
            setInputValue: action.bound,
            setInputSearchValue: action.bound,
            fetchOrganizationsMatch: action.bound,
        });

        //this._searchPageStore = searchPageStore;

        const dropdownValues: Option[] = [];
        (RootStore.locationStore.getSearchParams('types') ?? '').split(',').forEach((value) => {
            const option = DROPDOWN_OPTIONS.find((option) => option.value === value);
            if (option) {
                dropdownValues.push(option);
            }
        });
        this._dropdownValues = dropdownValues;

        this._navigateReaction = reaction(
            () => [this._inputValue ?? '', this._dropdownValues.map(({ value }) => value).join(',')],
            (values: string[]) => {
                history.replace({
                    pathname: window.location.pathname,
                    search: searchCreate({
                        search: values[0],
                        types: values[1],
                        page: String(searchPageStore.currentPage),
                    }),
                });
            },
        );
    }

    get githubOwnersMatch(): Option[] {
        return this._githubOwnersMatch;
    }

    get inputValue(): string | undefined {
        return this._inputValue;
    }

    get dropdownValues(): Option[] {
        return this._dropdownValues;
    }

    setDropdownValues = (values: Option[]): void => {
        this._dropdownValues = values;
    };

    setInputValue = (value: string): void => {
        this._inputValue = value;
    };

    setInputSearchValue = (value: string): void => {
        if (RootStore.githubOAuth.isLogin) {
            this._ThrottledFn(value);
            this._DebouncedFn(value);
        }

        startTransition(() => {
            this._inputValue = value;
        });
    };

    fetchOrganizationsMatch = async (queryParam: string): Promise<void> => {
        try {
            const result = await this._ApiStore.getApiRequest<GithubOwnersMatchApi>(
                `search/users?q=${queryParam}+type:org&sort=created&order=asc&per_page=5`,
                {
                    headers: { Accept: 'application/vnd.github.text-match+json' },
                },
            );
            runInAction(() => {
                this._githubOwnersMatch = normalizeGithubOwnersMatch(result.data).map((owner) => ({
                    key: owner.login,
                    value: owner.login,
                }));
            });
        } catch {
            runInAction(() => {
                this._githubOwnersMatch = [];
            });
        }
    };

    destroy(): void {
        this._navigateReaction();
    }
}
